package org.example.netty.test.nio.netty.chat.session;

import cn.hutool.core.lang.Assert;
import cn.hutool.crypto.digest.MD5;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.CharsetUtil;
import lombok.extern.slf4j.Slf4j;
import org.example.netty.test.nio.netty.chat.bean.JoinUserMessage;
import org.example.netty.test.nio.netty.chat.bean.SendGroupMessage;
import org.example.netty.test.nio.netty.chat.bean.User;
import org.example.netty.test.nio.netty.chat.common.UserStatus;
import org.example.netty.test.nio.netty.chat.util.FileUtil;
import org.example.netty.test.nio.netty.chat.util.NettyChannelUtil;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author zp
 * @version 1.0
 * @description: 全局的用户 信息
 * @date 2023/4/5 20:13
 */
@Slf4j
public class GlobalContent {
    // 全局的用户 使用ConcurrentHashMap 多线程 变量线程安全
    private final ConcurrentHashMap<String, UserSession> userMap = new ConcurrentHashMap<>();
    // 保存通道和用户ID之间的联系
    private final ConcurrentHashMap<String, Channel> userChannelMap = new ConcurrentHashMap<>();
    // 存放ID和name的映射
    private final ConcurrentHashMap<String, String> userNameMap = new ConcurrentHashMap<>();
    // 保存群聊的数据
    private final ConcurrentHashMap<String, Set<UserSession>> groupUserMap = new ConcurrentHashMap<>();
    private static final GlobalContent GLOBAL_CONTENT = new GlobalContent();

    private GlobalContent() {
        readUserInfo();
        // 测试群聊的方法
        //initUserSession();
    }

    /**
     * @description:  初始化的时候 加载已注册的用户的信息
     * @author zp
     * @date: 2023/5/20 15:14
     */
    private void readUserInfo() {
        try {
            List<User> users = FileUtil.readUserList();
            for (User user : users) {
                String userId = MD5.create().digestHex16(user.getUserName() + user.getPassword(), CharsetUtil.UTF_8);
                user.setStatus(UserStatus.REGISTER_STATUS);
                UserSession userSession = new UserSession();
                userSession.setUser(user);
                userMap.put(userId,userSession);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }

    }

    /**
     * @description: 初始化群聊用户 方便测试
     * @author zp
     * @date: 2023/4/29 16:11
     */
    private void initUserSession() {
        User zhangsan = new User();
        User lisi = new User();
        User wangwu = new User();

        zhangsan.setPassword("123456");
        lisi.setPassword("123456");
        wangwu.setPassword("123456");

        String zhangUserName = "zhangsan";
        zhangsan.setUserName(zhangUserName);
        String lisiUserName = "lisi";
        lisi.setUserName(lisiUserName);
        String wangwuUserName = "wangwu";
        wangwu.setUserName(wangwuUserName);

        String zhangsanUserId = MD5.create().digestHex16(zhangsan.getUserName() + zhangsan.getPassword(), CharsetUtil.UTF_8);
        zhangsan.setUserId(zhangsanUserId);
        String lisiUserId = MD5.create().digestHex16(lisi.getUserName() + lisi.getPassword(), CharsetUtil.UTF_8);
        lisi.setUserId(lisiUserId);
        String wangwuUserId = MD5.create().digestHex16(wangwu.getUserName() + wangwu.getPassword(), CharsetUtil.UTF_8);
        wangwu.setUserId(wangwuUserId);

        userNameMap.put(zhangUserName, zhangsanUserId);
        userNameMap.put(lisiUserName, lisiUserId);
        userNameMap.put(wangwuUserName, wangwuUserId);

        UserSession zhangsanUserSession = new UserSession();
        UserSession lisiUserSession = new UserSession();
        UserSession wangwuUserSession = new UserSession();

        zhangsanUserSession.setUser(zhangsan);
        lisiUserSession.setUser(lisi);
        wangwuUserSession.setUser(wangwu);


        userMap.put(zhangsan.getUserId(), zhangsanUserSession);
        userMap.put(lisi.getUserId(), lisiUserSession);
        userMap.put(wangwu.getUserId(), wangwuUserSession);
    }

    /**
     * @param groupName
     * @param userSessions
     * @description: 创建群聊
     * @author zp
     * @date: 2023/4/11 20:13
     */
    public void createGroup(String groupName, Set<UserSession> userSessions) {
        groupUserMap.put(groupName, userSessions);
    }

    /**
     * @param groupName
     * @return List<UserSession>
     * @description: 获取群聊的用户session
     * @author zp
     * @date: 2023/4/28 19:39
     */
    public Set<UserSession> getGroupUserSession(String groupName) {
        return groupUserMap.get(groupName);
    }

    /**
     * @param groupName
     * @return boolean
     * @description: 校验群名称是否重复
     * @author zp
     * @date: 2023/4/11 20:30
     */
    public boolean isExistGroupName(String groupName) {
        return groupUserMap.containsKey(groupName);
    }

    /**
     * @param groupName
     * @description: 加入群聊
     * @author zp
     * @date: 2023/4/11 20:14
     */
    public void joinGroup(String groupName) {
        // 全局的需要保存
        Set<UserSession> userSessions = groupUserMap.get(groupName);
        for (UserSession userSession : userSessions) {
            userSession.bindChatGroup(groupName);
        }
    }


    /**
     * @param userSession
     * @return List<String>
     * @description: 你不在的群聊列表
     * @author zp
     * @date: 2023/4/11 20:42
     */
    public Set<String> isNotInJoinGroupNames(UserSession userSession) {
        Set<String> groupNames = userSession.getGroupNames();
        if (groupNames == null || groupNames.size() == 0) {
            return groupUserMap.keySet();
        }
        return groupNames.stream().filter(name -> !groupUserMap.containsKey(name)).collect(Collectors.toSet());
    }

    /**
     * @param userSession
     * @return List<String>
     * @description: 你在的群聊列表
     * @author zp
     * @date: 2023/4/11 20:42
     */
    public Set<String> isInJoinGroupNames(UserSession userSession) {
        return userSession.getGroupNames();
    }

    /**
     * @return GlobalContent
     * @description: 获取单例对象
     * @author zp
     * @date: 2023/4/5 20:36
     */
    public static GlobalContent getInstance() {
        return GLOBAL_CONTENT;
    }


    /**
     * @param userId
     * @return UserSession
     * @description: 根据用户ID获取用户Session
     * @author zp
     * @date: 2023/4/5 20:17
     */
    public UserSession getUserSession(String userId) {
        return userMap.get(userId);
    }

    /**
     * @param joinUserMessage
     * @description: 创建单人聊天
     * @author zp
     * @date: 2023/4/12 19:11
     */
    public void addUserChat(JoinUserMessage joinUserMessage) {
        UserSession createUserSession = getSession(joinUserMessage.getCreateBuildUserName());
        UserSession byUserSession = getSession(joinUserMessage.getByUserName());

        Set<String> createChatNameList = createUserSession.getChatNameList();
        Set<String> byChatNameList = byUserSession.getChatNameList();
        String byUserName = byUserSession.getUser().getUserName();
        String createUserName = createUserSession.getUser().getUserName();

        // 只有相互不存在 才需要绑定 如果已经存在 则不需要重复绑定
        if (createChatNameList.size() > 0) {
            if (!createChatNameList.contains(byUserName)) {
                // 相互绑定
                createUserSession.bindChat(byUserName, byUserSession);
            }
        } else {
            createUserSession.bindChat(byUserName, byUserSession);
        }
        // 校验集合是否为空 如果为空 不校验直接添加
//        if (byChatNameList.size() > 0) {
//            if (!byChatNameList.contains(createUserName)) {
//                byUserSession.bindChat(createUserName, createUserSession);
//            }
//        } else {
//            byUserSession.bindChat(createUserName, createUserSession);
//        }

    }

    /**
     * @param ctx
     * @return Map<String>
     * @description: 获取单独聊天的列表
     * @author zp
     * @date: 2023/4/12 20:11
     */
    public Map<String, String> getUserChatList(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        UserSession userSession = NettyChannelUtil.getUserSession(channel);
        assert userSession != null;
        Set<String> chatNameList = userSession.getChatNameList();
        // 使用LinkedHashMap 保证有序性
        Map<String, String> map = new LinkedHashMap<>();
        for (String chatName : chatNameList) {
            // 遍历所有的单独聊天名称 和聊天的对方
            map.put(chatName, userSession.getUserChatUserSessionList(chatName).getUser().getUserName());
        }
        return map;
    }

    /**
     * @return List<String>
     * @description: 获取用户名称列表
     * @author zp
     * @date: 2023/4/5 20:25
     */
    public Set<String> getUserNames() {
        Set<String> list = new HashSet<>();
        for (Map.Entry<String, UserSession> entry : userMap.entrySet()) {
            list.add(entry.getValue().getUser().getUserName());
        }
        return list;
    }

    /**
     * @return List<String>
     * @description: 获取所有群聊的名称
     * @author zp
     * @date: 2023/4/16 17:54
     */
    public Set<String> getGroupNameList() {
        return groupUserMap.keySet();
    }

    /**
     * @param userName
     * @return boolean
     * @description: 判断用户名是否已存在 已存在就不可用
     * @author zp
     * @date: 2023/4/5 20:39
     */
    public boolean userNameExist(String userName) {
        Set<String> userNames = getUserNames();
        return userNames.contains(userName);
    }

    /**
     * @return List<String>
     * @description: 获取用户id列表
     * @author zp
     * @date: 2023/4/5 20:29
     */
    public Set<String> getUseIds() {
        Set<String> list = new HashSet<>();
        for (Map.Entry<String, UserSession> entry : userMap.entrySet()) {
            list.add(entry.getValue().getUser().getUserId());
        }
        return list;
    }

    /**
     * @param userId
     * @param userSession
     * @description: 绑定Session
     * @author zp
     * @date: 2023/4/5 20:26
     */
    public void bind(String userId, UserSession userSession, Channel channel) {
        userMap.put(userId, userSession);
        userChannelMap.put(userId, channel);
        userNameMap.put(userSession.getUser().getUserName(), userId);
    }

    /**
     * @param userId
     * @description: 解绑操作
     * @author zp
     * @date: 2023/4/5 20:30
     */
    public void unbind(String userId, String userName) {
        userMap.remove(userId);
        userNameMap.remove(userName);
        userChannelMap.remove(userId);
    }

    /**
     * @param userId
     * @return Channel
     * @description: 根据用户ID 获取对应的Channel
     * @author zp
     * @date: 2023/4/5 20:31
     */
    public Channel getUserChannelById(String userId) {
        UserSession userSession = userMap.get(userId);
        Assert.notNull(userSession, "用户不存在");
        return userChannelMap.get(userId);
    }

    /**
     * @param userName
     * @return Channel
     * @description: 根据用户名 获取用户channel
     * @author zp
     * @date: 2023/5/20 14:10
     */
    public Channel getUserChannelByName(String userName) {
        String userId = userNameMap.get(userName);
        UserSession userSession = userMap.get(userId);
        Assert.notNull(userSession, "用户不存在");
        return userChannelMap.get(userId);
    }

    /**
     * @param userNames
     * @return List<UserSession>
     * @description: 根据用户名集合获取UserSession集合
     * @author zp
     * @date: 2023/4/10 19:42
     */
    public Set<UserSession> getSessions(Set<String> userNames) {
        Set<UserSession> userSessions = new HashSet<>();
        for (String userName : userNames) {
            UserSession userSession = getSession(userName);
            userSessions.add(userSession);
        }
        return userSessions;
    }

    /**
     * @param userName
     * @return UserSession
     * @description: 根据用户名获取UserSession
     * @author zp
     * @date: 2023/4/10 19:44
     */
    public UserSession getSession(String userName) {
        String userId = userNameMap.get(userName);
        return getUserSession(userId);
    }

    /**
     * @description: 删除单独聊天
     * @author zp
     * @date: 2023/4/13 19:37
     */
    public void removeChat(String userChatName, String sendUserName) {
        UserSession recipientUserSession = getSession(userChatName);
        UserSession sendUserSession = getSession(sendUserName);

        Set<String> chatNameList = recipientUserSession.getChatNameList();
        if (chatNameList != null) {
            chatNameList.remove(sendUserSession.getUser().getUserName());
        }
        chatNameList = sendUserSession.getChatNameList();
        if (chatNameList != null) {
            chatNameList.remove(recipientUserSession.getUser().getUserName());
        }
    }

    /**
     * @param userName
     * @description: 删除群聊记录
     * @author zp
     * @date: 2023/4/14 19:31
     */
    public void removeGroupChat(String groupName, String userName) {
        Set<UserSession> userSessions = groupUserMap.get(groupName);
        UserSession session = getSession(userName);
        session.removeGroupChat(groupName);
        userSessions.remove(session);
        groupUserMap.put(groupName, userSessions);
    }

    /**
     * @param msg
     * @description: 发送群聊消息
     * @author zp
     * @date: 2023/5/17 20:18
     */
    public void sendGroup(SendGroupMessage msg) {
        String sender = msg.getSender();
        String groupName = msg.getGroupName();

        Set<UserSession> groupUserSession = getGroupUserSession(groupName);
        UserSession sendSession = getSession(sender);
        for (UserSession userSession : groupUserSession) {
            // 如果是发送者 就无需发送消息
            if (userSession.equals(sendSession)) {
                continue;
            }
            // 只有加入群聊的人 才会收到群聊消息
            if (sendSession.isInGroup(groupName)) {
                String userId = userSession.getUser().getUserId();
                getUserChannelById(userId).writeAndFlush(msg);
            }
        }
    }
}
